package com.ysynzehao.dao.utils;

import org.apache.commons.beanutils.BeanMap;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.query.internal.NativeQueryImpl;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2018/3/29.
 */
@NoRepositoryBean
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

    //实体管理类，对持久化实体做增删改查，自动义sq操作模板所需要的核心类
    public EntityManager entityManager;
    public Class<T> domainClass;

    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
        this.domainClass = domainClass;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Map> findAllByParams(String sql, Object... args) {
        //获取session
        Session session = (Session) entityManager.getDelegate();
        NativeQueryImpl q = (NativeQueryImpl) session.createSQLQuery(sql);
        //查询结果转map
        q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
        int i = 0;
        for (Object arg : args) {
            q.setParameter(++i, arg);
        }
        return q.list();
    }

    @Override
    public <T> List<Map> findAllByParams(String sql, T params) {
        Map paramMap = null;
        if (!(params instanceof Map)) {
            paramMap = new BeanMap(params);
        } else {
            paramMap = (Map<String, Object>) params;
        }
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}");
        sql = genericTokenParser.parse(sql);
        Object[] args = new Object[genericTokenParser.getMatchList().size()];
        int i = 0;
        for (String m : genericTokenParser.getMatchList()) {
            args[i++] = paramMap.get(m);
        }
        return findAllByParams(sql, args);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Page<Map> findPageByParams(String sql, Pageable pageable, Object... args) {
        Session session = (Session) entityManager.getDelegate();
        NativeQueryImpl q = (NativeQueryImpl) session.createSQLQuery(sql);
        q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
        int i = 0;
        for (Object arg : args) {
            q.setParameter(++i, arg);
        }

        List<Map> totalCount = q.list();
        q.setFirstResult(pageable.getPageSize() * (pageable.getPageNumber() - 1));
        q.setMaxResults(pageable.getPageSize());
        List<Map> pageCount = q.list();
        Page<Map> pages = new PageImpl<>(pageCount, pageable, totalCount.size());
        return pages;
    }

    @Override
    public <T> Page<Map> findPageByParams(String sql, Pageable pageable, T params) {
        Map paramMap = null;
        if (!(params instanceof Map)) {
            paramMap = new BeanMap(params);
        } else {
            paramMap = (Map<String, Object>) params;
        }
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}");
        sql = genericTokenParser.parse(sql);
        Object[] args = new Object[genericTokenParser.getMatchList().size()];
        int i = 0;
        for (String m : genericTokenParser.getMatchList()) {
            args[i++] = paramMap.get(m);
        }
        return findPageByParams(sql, pageable, args);
    }

}